package org.zeapp.opencloud.framework.cloud.impl.dropbox;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.zeapp.opencloud.framework.cloud.Cloud;
import org.zeapp.opencloud.framework.cloud.CloudEntry;
import org.zeapp.opencloud.framework.cloud.CloudException;
import org.zeapp.opencloud.framework.cloud.CloudFile;
import org.zeapp.opencloud.framework.cloud.CloudFolder;
import org.zeapp.opencloud.framework.preference.Preference;

import com.dropbox.core.DbxClient;
import com.dropbox.core.DbxEntry;
import com.dropbox.core.DbxEntry.Folder;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.DbxWriteMode;

/**
 * The Dropbox implementation of the Cloud service.
 * 
 * @author Amphiprion
 * 
 */
public class DropboxCloud implements Cloud {
	private DbxClient client;

	/**
	 * Create a new DropboxCloud object
	 * 
	 * @param preference
	 */
	protected DropboxCloud(Preference preference) throws CloudException {
		String token = preference.get(DropBoxDriver.TOKEN_KEY);
		if (token == null) {
			throw new CloudException(
					"No token authorization found. The token must exists in preference.",
					"DROPBOX00005");
		}
		try {
			DbxRequestConfig config = new DbxRequestConfig("ZeAPP Open Cloud",
					Locale.getDefault().toString());
			client = new DbxClient(config, token);
		} catch (Throwable e) {
			throw new CloudException("Cannot create DropboxCloud service.",
					"DROPBOX00004", e);
		}
	}

	@Override
	public List<CloudEntry> browseDirectory(String remotePath)
			throws CloudException {
		try {
			List<CloudEntry> result = new ArrayList<CloudEntry>();
			DbxEntry.WithChildren listing = client
					.getMetadataWithChildren(remotePath);
			for (DbxEntry child : listing.children) {
				if (child.isFile()) {
					com.dropbox.core.DbxEntry.File file = child.asFile();
					CloudFile entry = new CloudFile();
					entry.setName(child.name);
					entry.setPath(child.path);
					entry.setSize(file.numBytes);
					entry.setLasModified(file.lastModified);
					result.add(entry);
				} else {
					CloudFolder entry = new CloudFolder();
					entry.setName(child.name);
					entry.setPath(child.path);
					result.add(entry);
				}
			}
			return result;
		} catch (Throwable e) {
			throw new CloudException("Cannot browse the remote folder "
					+ remotePath, "DROPBOX00006", e);
		}
	}

	@Override
	public CloudFile getFile(String remotePath, OutputStream outputStream)
			throws CloudException {
		try {
			DbxEntry.File downloadedFile = client.getFile(remotePath, null,
					outputStream);
			CloudFile entry = new CloudFile();
			entry.setLasModified(downloadedFile.lastModified);
			entry.setName(downloadedFile.name);
			entry.setPath(downloadedFile.path);
			entry.setSize(downloadedFile.numBytes);

			return entry;
		} catch (Throwable e) {
			throw new CloudException("Cannot retrieve the remote file "
					+ remotePath, "DROPBOX00007", e);
		}
	}

	@Override
	public CloudFile uploadFile(String remotePath, long fileSize,
			InputStream inputStream) throws CloudException {
		try {
			DbxEntry.File uploadedFile = client.uploadFile(remotePath,
					DbxWriteMode.force(), fileSize, inputStream);
			// System.out.println(uploadedFile);
			CloudFile entry = new CloudFile();
			entry.setLasModified(uploadedFile.lastModified);
			entry.setName(uploadedFile.name);
			entry.setPath(uploadedFile.path);
			entry.setSize(uploadedFile.numBytes);
			return entry;
		} catch (Throwable e) {
			throw new CloudException("Cannot upload file as " + remotePath,
					"DROPBOX00008", e);
		}
	}

	@Override
	public CloudFolder createFolder(String remotePath) throws CloudException {

		try {
			Folder folder = client.createFolder(remotePath);
			if (folder == null) {
				return null;
			}
			CloudFolder entry = new CloudFolder();
			entry.setName(folder.name);
			entry.setPath(folder.path);
			return entry;
		} catch (Throwable e) {
			throw new CloudException("Cannot create the remote folder "
					+ remotePath, "DROPBOX00009", e);
		}
	}
}
